#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
#include <vector>

#include "Log.hpp"
using namespace LogMudule;

#define BUFFER_DEFAULT_SIZE 1024

class Buffer
{
public:
    Buffer()
        : _read_index(0),
          _write_index(0),
          _buffer(BUFFER_DEFAULT_SIZE)
    {
    }

    // 获取_buffer首位地址
    char *Begin()
    {
        return (char *)(&(*_buffer.begin()));
    }

    // 获取可读位置的地址
    char *ReadPtr()
    {
        return Begin() + _read_index;
    }

    // 获取可写位置的地址
    char *WritePtr()
    {
        return Begin() + _write_index;
    }

    // 可读区域大小
    int64_t ReadSize()
    {
        return _write_index - _read_index;
    }

    // 头部可写区域大小
    int64_t HeadWriteSize()
    {
        return _read_index;
    }

    // 尾部可写区域大小
    int64_t TailWriteSize()
    {
        return _buffer.size() - _write_index;
    }

    // 读指针进行偏移
    void ReadIndexSkewing(uint64_t len)
    {
        assert(len <= ReadSize());
        _read_index += len;
    }

    // 写指针进行偏移
    void WriteIndexSkewing(uint64_t len)
    {
        assert(len <= TailWriteSize());
        _write_index += len;
    }

    // 保证有足够空间插入
    void GuaranteeSpaceEnough(uint64_t len)
    {
        // 1.尾部有足够空间
        if (len <= TailWriteSize())
        {
            return;
        }
        // 2.头部+尾部有足够空间
        else if (len <= HeadWriteSize() + TailWriteSize())
        {
            uint64_t readsize = ReadSize();
            std::copy(ReadPtr(), WritePtr(), Begin());
            _read_index = 0;
            _write_index = readsize;
        }
        // 3.需要扩容
        else
        {
            _buffer.resize(_buffer.size() + len);
        }
    }

    // 进行写入
    void Write(const void *in, uint64_t len)
    {
        if(len == 0)
        {
            return;
        }

        GuaranteeSpaceEnough(len);
        const char *temp_in = (const char *)in;
        std::copy(temp_in, temp_in + len, WritePtr());
    }

    // 进行写入并偏移
    void WritePush(const void *in, uint64_t len)
    {
        Write(in, len);
        WriteIndexSkewing(len);
    }

    // 进行写入 - string
    void WriteString(const std::string &in)
    {
        Write(in.c_str(), in.size());
    }

    // 进行写入并偏移 - string
    void WriteStringPush(const std::string &in)
    {
        Write(in.c_str(), in.size());
        WriteIndexSkewing(in.size());
    }

    // 进行写入 - Buffer
    void WriteBuffer(Buffer &in)
    {
        Write(in.Begin(), in.ReadSize());
    }

    // 进行写入并偏移 - Buffer
    void WriteBufferPush(Buffer &in)
    {
        WriteBuffer(in);
        WriteIndexSkewing(in.ReadSize());
    }

    // 进行读取
    void Read(void *out, uint64_t len)
    {
        assert(len <= ReadSize());
        char *read_ptr = ReadPtr();
        std::copy(read_ptr, read_ptr + len, (char *)out);
    }

    // 进行读取并偏移
    void ReadPop(void *out, uint64_t len)
    {
        Read(out, len);
        ReadIndexSkewing(len);
    }

    // 进行读取 - string
    std::string ReadString(uint64_t len)
    {
        if (len == 0)
            return "";
        std::string ret;
        ret.resize(len);

        Read(&ret[0], len);

        return ret;
    }

    // 进行读取并偏移
    std::string ReadStringPop(uint64_t len)
    {
        std::string ret = ReadString(len);
        ReadIndexSkewing(len);
        return ret;
    }

    // 进行行读取
    std::string GetLine()
    {
        char *res = FindLine();
        if (res == nullptr)
            return "";

        return ReadString(res - ReadPtr() + 1);
    }

    // 进行行读取并进行偏移
    std::string GetLinePop()
    {
        std::string res = GetLine();
        ReadIndexSkewing(res.size());
        return res;
    }

    // 清空缓冲区
    void Clear()
    {
        _read_index = 0;
        _write_index = 0;
    }

    ~Buffer() = default;

private:
    char *FindLine()
    {
        char *ret = (char *)memchr(ReadPtr(), '\n', ReadSize());
        return ret;
    }

private:
    std::vector<char> _buffer;
    uint64_t _read_index;
    uint64_t _write_index;
};
